package com.ai.wxy.spring.auth.security;

import com.ai.wxy.spring.auth.service.IUrlRoleService;
import com.ai.wxy.spring.auth.util.JwtTokenUtil;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * Default ConfigurerAdapter
 *
 * @author 石头
 * @Date 2019/10/30
 * @Version 1.0
 **/
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Order(SecurityProperties.BASIC_AUTH_ORDER)
public class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {
    private String loginPath;

    private JwtAuthenticationEntryPoint unauthorizedHandler;
    private JwtAuthorizationTokenFilter authenticationTokenFilter;
    private IUrlRoleService urlRoleService;
    @Setter
    private AccessDecisionManager accessDecisionManager;
    @Setter
    private org.springframework.security.web.access.AccessDeniedHandler accessDeniedHandler;

    public DefaultConfigurerAdapter(JwtTokenUtil jwtTokenUtil, JwtAuthenticationEntryPoint unauthorizedHandler, JwtAuthorizationTokenFilter authenticationTokenFilter, IUrlRoleService urlRoleService){
        this.unauthorizedHandler       = unauthorizedHandler;
        this.authenticationTokenFilter = authenticationTokenFilter;
        this.urlRoleService            = urlRoleService;
        this.loginPath                 = jwtTokenUtil.getLoginPath();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //禁用缓存
        http.headers().cacheControl();
        // 禁用 CSRF
        http.csrf().disable()
                // 授权异常
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                // 权限不足
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
                // 不创建会话
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
                // 放行OPTIONS请求
                .antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
                // 放行登录的path
                .antMatchers( HttpMethod.POST,"/auth"+loginPath).anonymous()

                // swagger start
                .antMatchers("/swagger-ui.html").anonymous()
                .antMatchers("/swagger-resources/**").anonymous()
                .antMatchers("/webjars/**").anonymous()
                .antMatchers("/*/api-docs").anonymous()
                // swagger end

                // 所有请求都需要认证
                .anyRequest().authenticated()
                // 自定义FilterInvocationSecurityMetadataSource
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>(){
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O fsi) {
                        fsi.setSecurityMetadataSource(new URLFilterInvocationSecurityMetadataSource(fsi.getSecurityMetadataSource(),urlRoleService));
                        fsi.setAccessDecisionManager(accessDecisionManager);
                        return fsi;
                    }
                }).and()
                // 防止iframe 造成跨域
                .headers().frameOptions().disable();

        http.addFilterBefore(authenticationTokenFilter,UsernamePasswordAuthenticationFilter.class);
    }
}
